perm filename C5[CLS,LSP] blob
sn#871199 filedate 1989-03-17 generic text, type C, neo UTF8
COMMENT ā VALID 00002 PAGES
C REC PAGE DESCRIPTION
C00001 00001
C00002 00002 %Start Part 5 of 6 concep.tex
C00039 ENDMK
Cā;
%Start Part 5 of 6 concep.tex
Initialization arguments are used in four situations: when making an
instance, when re-initializing an instance, when updating an instance to
conform to a redefined class, and when updating an instance to conform
to the definition of a different class.
Because initialization arguments are used to control the creation and
initialization of an instance of some particular class, we say that an
initialization argument is ``an initialization argument for'' that
class.
\endsubSection%{Initialization Arguments}
\beginsubSection{Declaring the Validity of Initialization Arguments}
Initialization arguments are checked for validity in each of the four
situations that use them. An initialization argument may be valid in
one situation and not another. For example, the system-supplied
primary method for {\bf make-instance} defined for the class {\bf
standard-class} checks the validity of its initialization arguments
and signals an error if an initialization argument is supplied that is
not declared as valid in that situation.
\newpage
There are two means for declaring initialization arguments valid.
\beginlist
\item{\bull} Initialization arguments that fill slots are declared as
valid by the {\bf :initarg} slot option to {\bf defclass}. The {\bf
:initarg} slot option is inherited from superclasses. Thus the set of
valid initialization arguments that fill slots for a class is the
union of the initialization arguments that fill slots declared as
valid by that class and its superclasses. Initialization arguments
that fill slots are valid in all four contexts.
\item{\bull} Initialization arguments that supply arguments to methods
are declared as valid by defining those methods. The keyword name of
each keyword parameter specified in the method's lambda-list becomes
an initialization argument for all classes for which the method is
applicable. Thus method inheritance controls the set of valid
initialization arguments that supply arguments to methods. The
generic functions for which method definitions serve to declare
initialization arguments valid are as follows:
\itemitem{--} Making an instance of a class: {\bf allocate-instance},
{\bf initialize-instance}, and {\bf shared-initialize}.
Initialization arguments declared as valid by these methods are
valid when making an instance of a class.
\itemitem{--} Re-initializing an instance: {\bf reinitialize-instance}
and {\bf shared-initialize}.
Initialization arguments declared as valid by these methods are
valid when re-initializing an instance.
\itemitem{--} Updating an instance to conform to a redefined class:
{\bf update-instance-for-redefined-class} and {\bf shared-initialize}.
Initialization arguments declared as valid by these methods are
valid when updating an instance to conform to a redefined class.
\itemitem{--} Updating an instance to conform to the definition of a
different class: {\bf update-instance-for-different-class} and {\bf
shared-initialize}.
Initialization arguments declared as valid by these methods are
valid when updating an instance to conform to the definition
of a different class.
\endlist
The set of valid initialization arguments for a class is the set of
valid initialization arguments that either fill slots or supply
arguments to methods, along with the predefined initialization
argument {\bf :allow-other-keys}. The default value for {\bf
:allow-other-keys} is {\bf nil}. The meaning of {\bf
:allow-other-keys} is the same as when it is passed to an ordinary
function.
\endsubSection%{Declaring the Validity of Initialization Arguments}
\beginsubSection{Defaulting of Initialization Arguments}
A {\bit default value form\/} can be supplied for an initialization
argument by using the {\bf :default-initargs} class option. If an
initialization argument is declared valid by some particular class,
its default value form might be specified by a different class.
In this case {\bf :default-initargs} is used to supply a default value
for an inherited initialization argument.
The {\bf :default-initargs} option is used only to provide default
values for initialization arguments; it does not declare a symbol as a
valid initialization argument name. Furthermore, the {\bf
:default-initargs} option is used only to provide default values for
initialization arguments when making an instance.
The argument to the {\bf :default-initargs} class option is a list of
alternating initialization argument names and forms. Each form is the
default value form for the corresponding initialization
argument. The default value form of an initialization
argument is used and evaluated only if that initialization argument
does not appear in the arguments to {\bf make-instance} and is not
defaulted by a more specific class. The default value form is
evaluated in the lexical environment of the {\bf defclass} form that
supplied it; the resulting value is used as the initialization
argument's value.
The initialization arguments supplied to {\bf make-instance} are combined
with defaulted initialization arguments to produce a {\bit
defaulted initialization argument list}. A defaulted initialization
argument list is a list of alternating initialization argument names and
values in which unsupplied initialization arguments are defaulted and in
which the explicitly supplied initialization arguments appear earlier in
the list than the defaulted initialization arguments. Defaulted
initialization arguments are ordered according to the order in the class
precedence list of the classes that supplied the default values.
There is a distinction between the purposes of the {\bf
:default-initargs} and the {\bf :initform} options with respect to the
initialization of slots. The {\bf :default-initargs} class option
provides a mechanism for the user to give a default value form
for an initialization argument without knowing whether the
initialization argument initializes a slot or is passed to a method.
If that initialization argument is not explicitly supplied in a call
to {\bf make-instance}, the default value form is used, just
as if it had been supplied in the call. In contrast, the {\bf
:initform} slot option provides a mechanism for the user to give a
default initial value form for a slot. An {\bf :initform} form is
used to initialize a slot only if no initialization argument
associated with that slot is given as an argument to {\bf
make-instance} or is defaulted by {\bf :default-initargs}.
The order of evaluation of default value forms for initialization
arguments and the order of evaluation of {\bf :initform} forms are
undefined. If the order of evaluation is important, {\bf
initialize-instance} or {\bf shared-initialize} methods should be used
instead.
\endsubSection%{Defaulting of Initialization Arguments}
\beginsubSection{Rules for Initialization Arguments}
The {\bf :initarg} slot option may be specified more than
once for a given slot.
The following rules specify when initialization arguments may be
multiply defined:
\beginlist
\item{\bull} A given initialization argument can be used to
initialize more than one slot if the same initialization argument name
appears in more than one {\bf :initarg} slot option.
\item{\bull} A given initialization argument name can appear
in the lambda-list of more than one initialization method.
\item{\bull} A given initialization argument name can
appear both in an {\bf :initarg} slot option and in the lambda-list
of an initialization method.
\endlist
If two or more initialization arguments that initialize
the same slot are given in the arguments to {\bf make-instance}, the
leftmost of these initialization arguments in the initialization
argument list supplies the value, even if the initialization arguments
have different names.
If two or more different initialization arguments that
initialize the same slot have default values and none is given
explicitly in the arguments to {\bf make-instance}, the initialization
argument that appears in a {\bf :default-initargs} class option in the
most specific of the classes supplies the value. If a single {\bf
:default-initargs} class option specifies two or more initialization
arguments that initialize the same slot and none is given explicitly
in the arguments to {\bf make-instance}, the leftmost in the {\bf
:default-initargs} class option supplies the value, and the values of
the remaining default value forms are ignored.
Initialization arguments given explicitly in the
arguments to {\bf make-instance} appear to the left of defaulted
initialization arguments. Suppose that the classes $C\sub 1$ and
$C\sub 2$ supply the values of defaulted initialization arguments for
different slots, and suppose that $C\sub 1$ is more specific than
$C\sub 2$; then the defaulted initialization argument whose value is
supplied by $C\sub 1$ is to the left of the defaulted initialization
argument whose value is supplied by $C\sub 2$ in the defaulted
initialization argument list. If a single {\bf :default-initargs}
class option supplies the values of initialization arguments for two
different slots, the initialization argument whose value is specified
farther to the left in the {\bf default-initargs} class option appears
farther to the left in the defaulted initialization argument list.
If a slot has both an {\bf :initform} form and an {\bf
:initarg} slot option, and the initialization argument is defaulted
using {\bf :default-initargs} or is supplied to {\bf make-instance},
the captured {\bf :initform} form is neither used nor evaluated.
The following is an example of the above rules:
\screen!
(defclass q () ((x :initarg a)))
(defclass r (q) ((x :initarg b))
(:default-initargs a 1 b 2))
\endscreen!
$$\vbox{\halign{\strut#\hfil&\quad\hfil#\hfil&\quad\hfil#\hfil\cr
{}&\bf Defaulted&{}\cr
\bf Form&\bf Initialization Argument List&\bf Contents of Slot\cr
\noalign{\hrule}
{\tt (make-instance 'r)}&{\tt (a 1 b 2)}&{\tt 1}\cr
{\tt (make-instance 'r 'a 3)}&{\tt (a 3 b 2)}&{\tt 3}\cr
{\tt (make-instance 'r 'b 4)}&{\tt (b 4 a 1)}&{\tt 4}\cr
{\tt (make-instance 'r 'a 1 'a 2)}&{\tt (a 1 a 2 b 2)}&{\tt 1}\cr}}$$
\endsubSection%{Rules for Initialization arguments}
\beginsubSection{Shared-Initialize}
The generic function {\bf shared-initialize} is used to fill the slots
of an instance using initialization arguments and {\bf :initform}
forms when an instance is created, when an instance is re-initialized,
when an instance is updated to conform to a redefined class, and when
an instance is updated to conform to a different class. It uses
standard method combination. It takes the following arguments: the
instance to be initialized, a specification of a set of names of slots
accessible in that instance, and any number of initialization
arguments. The arguments after the first two must form an initialization
argument list.
The second argument to {\bf shared-initialize} may be one of the following:
\beginlist
\item{\bull} It can be list of slot names, which specifies
the set of those slot names.
\item{\bull} It can be {\bf nil}, which specifies the empty set of
slot names.
\item{\bull} It can be the symbol {\bf t}, which specifies the set of
all of the slots.
\endlist
There is a system-supplied primary method for {\bf
shared-initialize} whose first parameter specializer is the class {\bf
standard-object}. This method behaves as follows on each slot,
whether shared or local:
\beginlist
\item{\bull} If an initialization argument in the initialization
argument list specifies a value for that slot, that value is stored
into the slot, even if a value has already been stored in the slot
before the method is run. The affected slots are independent of which
slots are indicated by the second argument to {\bf shared-initialize}.
\item{\bull} Any slots indicated by the second argument that are still
unbound at this point are initialized according to their {\bf
:initform} forms. For any such slot that has an {\bf :initform} form,
that form is evaluated in the lexical environment of its defining {\bf
defclass} form and the result is stored into the slot. For example,
if a {\bf :before} method stores a value in the slot, the {\bf
:initform} form will not be used to supply a value for the slot. If
the second argument specifies a name that does not correspond to any
slots accessible in the instance, the results are unspecified.
\item{\bull} The rules mentioned in the section ``Rules for
Initialization Arguments'' are obeyed.
\endlist
The generic function {\bf shared-initialize} is called by the
system-supplied primary methods for {\bf reinitialize-instance}, {\bf
update-instance-for-different-class}, {\bf
update-instance-for-redefined-class}, and {\bf
initialize-instance}. Thus, methods can be written for {\bf
shared-initialize} to specify actions that should be taken in all of
these contexts.
\endsubSection%{Shared-Initialize}
\beginsubSection{Initialize-Instance}
The generic function {\bf initialize-instance} is called by {\bf
make-instance} to initialize a newly created instance. It uses
standard method combination. Methods for {\bf
initialize-instance} can be defined in order to perform any
initialization that cannot be achieved with the simple slot-filling
mechanisms.
During initialization, {\bf initialize-instance} is invoked
after the following actions have been taken:
\beginlist
\item{\bull} The defaulted initialization argument list has been computed by
combining the supplied initialization argument list with any default
initialization arguments for the class.
\item{\bull} The validity of the defaulted initialization argument
list has been checked. If any of the initialization arguments has not
been declared as valid, an error is signaled.
\item{\bull} A new instance whose slots are unbound has been created.
\endlist
The generic function {\bf initialize-instance} is called with the
new instance and the defaulted initialization arguments. There is
a system-supplied primary method for {\bf initialize-instance}
whose parameter specializer is the class {\bf standard-object}. This
method calls the generic function {\bf shared-initialize} to fill in
the slots according to the initialization arguments and the {\bf
:initform} forms for the slots; the generic function {\bf
shared-initialize} is called with the following arguments: the instance,
{\bf t}, and the defaulted initialization arguments.
Note that {\bf initialize-instance} provides the defaulted
initialization argument list in its call to {\bf shared-initialize},
so the first step performed by the system-supplied primary method for
{\bf shared-initialize} takes into account both the initialization
arguments provided in the call to {\bf make-instance} and the
defaulted initialization argument list.
Methods for {\bf initialize-instance} can be defined to specify
actions to be taken when an instance is initialized. If only {\bf :after}
methods for {\bf initialize-instance} are defined, they will be
run after the system-supplied primary method for initialization and
therefore will not interfere with the default behavior of {\bf
initialize-instance}.
The \OS\ provides two functions that are useful in the bodies of {\bf
initialize-instance} methods. The function {\bf slot-boundp}
returns a boolean value that indicates whether a specified slot has a
value; this provides a mechanism for writing {\bf :after} methods for
{\bf initialize-instance} that initialize slots only if they have
not already been initialized. The function {\bf slot-makunbound}
causes the slot to have no value.
\endsubSection%{INITIALIZE-INSTANCE}
\beginsubSection{Definitions of Make-Instance and Initialize-Instance}
The generic function {\bf make-instance} behaves as if it were defined as
follows, except that certain optimizations are permitted:
\screen!
(defmethod make-instance ((class standard-class) &rest initargs)
(setq initargs (default-initargs class initargs))
...
(let ((instance (apply #'allocate-instance class initargs)))
(apply #'initialize-instance instance initargs)
instance))
(defmethod make-instance ((class-name symbol) &rest initargs)
(apply #'make-instance (find-class class-name) initargs))
\endscreen!
%This is the code:
%(defmethod make-instance ((class standard-class) &rest initargs)
% (setq initargs (default-initargs class initargs))
% (let* ((proto (class-prototype class))
% (methods
% (append
% (compute-applicable-methods #'allocate-instance `(,class))
% (compute-applicable-methods #'initialize-instance `(,proto))
% (compute-applicable-methods #'shared-initialize `(,proto nil)))))
% (unless
% (subsetp
% (let ((keys '()))
% (do ((plist initargs (cddr plist)))
% ((null plist) keys)
% (push (car plist) keys)))
% (union
% (class-slot-initargs class)
% (reduce #'union (mapcar #'function-keywords methods))))
% (error ...)))
% (let ((instance (apply #'allocate-instance class initargs)))
% (apply #'initialize-instance instance initargs)
% instance))
The elided code in the definition of {\bf make-instance} checks the
supplied initialization arguments to determine whether an initialization
argument was supplied that neither filled a slot nor supplied an argument
to an applicable method. This check could be implemented using the generic
functions {\bf class-prototype}, {\bf compute-applicable-methods}, {\bf
function-keywords}, and {\bf class-slot-initargs}. See Chapter~3 for a
description of this initialization argument check.
The generic function {\bf initialize-instance} behaves as if it were
defined as follows, except that certain optimizations are permitted:
\screen!
(defmethod initialize-instance ((instance standard-object) &rest initargs)
(apply #'shared-initialize instance t initargs)))
\endscreen!
These procedures can be customized at either the Programmer Interface level,
the meta-object level, or both.
Customizing at the Programmer Interface level includes using the {\bf
:initform}, {\bf :initarg}, and {\bf :default-initargs} options to
{\bf defclass}, as well as defining methods for {\bf make-instance}
and {\bf initialize-instance}. It is also possible to define
methods for {\bf shared-initialize}, which would be invoked by the
generic functions {\bf reinitialize-instance}, {\bf
update-instance-for-redefined-class}, {\bf
update-instance-for-different-class}, and {\bf
initialize-instance}. The meta-object level supports additional
customization by allowing methods to be defined on {\bf
make-instance}, {\bf default-initargs}, and {\bf
allocate-instance}. Chapters~2 and~3 document each of these generic
functions and the system-supplied primary methods.
Implementations are permitted to make certain optimizations to {\bf
initialize-instance} and {\bf shared-initialize}. The
description of {\bf shared-initialize} in Chapter~2 mentions the
possible optimizations.
Because of optimization, the check for valid initialization arguments
might not be implemented using the generic functions {\bf
class-prototype}, {\bf compute-applicable-methods}, {\bf
function-keywords}, and {\bf class-slot-initargs}. In addition,
methods for the generic function {\bf default-initargs}, and the
system-supplied primary methods for {\bf allocate-instance}, {\bf
initialize-instance}, and {\bf shared-initialize} might not be called on
every call to {\bf make-instance} or might not receive exactly the
arguments that would be expected.
\endsubSection%{Definitions of MAKE-INSTANCE and Initialize-Instance}
\endSection%{Object Creation and Initialization}
\beginSection{Redefining Classes}
A class that is an instance of {\bf standard-class} can be redefined
if the new class will also be an instance of {\bf standard-class}.
Redefining a class modifies the existing class object to reflect the
new class definition; it does not create a new class object for the
class. Any method object created by a {\bf :reader}, {\bf :writer}, or
{\bf :accessor} option specified by the old {\bf defclass} form is
removed from the corresponding generic function.
Methods specified by the new {\bf defclass} form are added.
% any function specified by the {\bf :constructor}
% option of the old {\bf defclass} form is removed from the
% corresponding symbol function cell.
When the class $C$ is redefined, changes are propagated to its instances
and to instances of any of its subclasses. Updating such an
instance occurs at an implementation-dependent time, but no later than
the next time a slot of that instance is read or written. Updating an
instance does not change its identity as defined by the {\bf eq}
function. The updating process may change the slots of that
particular instance, but it does not create a new instance. Whether
updating an instance consumes storage is implementation dependent.
Note that redefining a class may cause slots to be added or deleted.
If a class is redefined in a way that changes the set of local slots
accessible in instances, the instances will be updated. It is
implementation dependent whether instances are updated if a class is
redefined in a way that does not change the set of local slots
accessible in instances.
The value of a slot that is specified as shared both in the old class
and in the new class is retained. If such a shared slot was unbound
in the old class, it will be unbound in the new class. Slots that
were local in the old class and that are shared in the new class are
initialized. Newly added shared slots are initialized.
Each newly added shared slot is set to the result of evaluating the
captured {\bf :initform} form for the slot that was specified in the
{\bf defclass} form for the new class. If there is no {\bf :initform}
form, the slot is unbound.
If a class is redefined in such a way that the set of local slots
accessible in an instance of the class is changed, a two-step process
of updating the instances of the class takes place. The process may
be explicitly started by invoking the generic function {\bf
make-instances-obsolete}. This two-step process can happen in other
circumstances in some implementations. For example, in some
implementations this two-step process will be triggered if the order
of slots in storage is changed.
The first step modifies the structure of the instance by adding new
local slots and discarding local slots that are not defined in the new
version of the class.
The second step initializes the newly added local slots and performs
any other user-defined actions. These two steps are further specified
in the next two sections.
%End Part 5 of 6 concep.tex